package redis

import (
	"errors"
	"github.com/go-redis/redis"
	"math"
	"strconv"
	"time"
)

//投票的几种情况：
//direction=1时，有两种情况：
//1：之前没有投过票，现在投赞成票   -->更新分数和投票记录 差值的绝对值：1 +432
//2：之前投反对票，现在改投赞成票   -->更新分数和投票记录 差值的绝对值：2 +432*2
//direction=0时，有两种情况：
//1：之前投反对票，现在取消投票    -->更新分数和投票记录 差值的绝对值：1 +432
//2：之前投赞成票，现在取消投票    -->更新分数和投票记录 差值的绝对值：1 -432
//direction=-1时，有两种情况：
//1：之前没有投票，现在投反对票    -->更新分数和投票记录 差值的绝对值：1 -432
//2：之前投赞成票，现在投反对票    -->更新分数和投票记录 差值的绝对值：2 -432*2
//
//投票的限制
//每个帖子发表之日起一个星期之内允许用户投票，超过一个星期就不允许再投票了
//1.到期之后将 redis中保存的赞成票数及反对票数存储到mysql表中
//2.到期之后删除那个KeyPostVoteZSetPF

const (
	oneWeekInSeconds = 7 * 24 * 3600
	scorePerVote     = 432 //每一票的分数
)

var (
	ErrVoteTimeExpire = errors.New("投票时间已过")
	ErrVoteRepested = errors.New("不允许重复投票")
)

func CreatePost(postID ,communityID int64) error {

	pipeline := client.TxPipeline()
	//帖子时间
	pipeline.ZAdd(getRedisKey(KeyPostTimeZSet), redis.Z{
		Score:  float64(time.Now().Unix()),
		Member: postID,
	})
	//帖子分数
	pipeline.ZAdd(getRedisKey(KeyPostScoreZSet), redis.Z{
		Score:  float64(time.Now().Unix()),
		Member: postID,
	})
	//更新：把帖子id加到社区的set
	cKey:=getRedisKey(KeyCommunitySetPF+strconv.Itoa(int(communityID)))
	pipeline.SAdd(cKey,postID)
	_, err := pipeline.Exec()
	return err
}
func VoteForPost(userID, postID string, value float64) error {
	//1.判断投票的限制
	//去Redis取帖子发布时间
	postTime := client.ZScore(getRedisKey(KeyPostTimeZSet), postID).Val()
	if float64(time.Now().Unix())-postTime > oneWeekInSeconds {
		return ErrVoteTimeExpire
	}
	//2和3需要放在一个pipeline事务中操作
	//2.更新分数
	//先查之前的投票的记录
	ov := client.ZScore(getRedisKey(KeyPostVotedZSetPF+postID), userID).Val()
	//更新：如果这一次投票的值和之前保存的值一致，就提示不允许重复投票
	if value==ov{
		return ErrVoteRepested
	}
	var op float64
	if value > ov {
		op = 1
	} else {
		op = -1
	}
	diff := math.Abs(ov - value) //计算两次投票的差值
	pipeline := client.TxPipeline()
	pipeline.ZIncrBy(getRedisKey(KeyPostScoreZSet), op*diff*scorePerVote, postID)
	//3.记录用户为该贴子投票的数据
	if value == 0 {
		pipeline.ZRem(getRedisKey(KeyPostVotedZSetPF+postID), postID)
	} else {
		pipeline.ZAdd(getRedisKey(KeyPostVotedZSetPF+postID), redis.Z{
			Score:  value,
			Member: userID,
		})
	}
	_, err := pipeline.Exec()
	return err
}
